//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<XAppDesktop.cpp>
///	@path	~/src/appear/xwin/
///	@date	2008/09/07
///	@desc	.

#define _FULLAPI
#include "config/config.h"

#include "lib/utilities/observer.h"

#include "object/CVar.h"

#include "graphics/IRenderer.h"

#include "gui/composite/composition.h"
#include "gui/xgui/XFrame.h"
#include "gui/xgui/XTagLayout.h"

#include "appear/xwin/XAppDesktop.h"
#include "appear/xwin/XAppFrame.h"
#include "appear/xwin/XAppPopup.h"
#include "appear/xwin/XFlipFrame.h"

#include "appear/xgfx/XGfxFade.h"
#include "appear/xgfx/XGfxShow.h"
#include "appear/xgfx/XGfxSlide.h"

namespace xeres {

	static const float HOVER_TIME = 0.7f;
	static const int TIPS_WIDTH = 300;

	IMPL_IOBJECT_CLASS( XAppDesktop );
	
	// XAppDesktop
	XAppDesktop::XAppDesktop( ImageResource * img_res )
		: XDesktop()
		, m_imageResource( img_res )
	{
		// Register class
		IOBJECT_REGISTER_CLASS( XAppFrame );
		IOBJECT_REGISTER_CLASS( XAppPopup );
		IOBJECT_REGISTER_CLASS( XFlipFrame );

 		m_tips = new XAppPopup( make_rect<int>( 0 , 0 , TIPS_WIDTH + 6 , 30 ) );
		XTagLayout * layout = new XTagLayout( StyleFont::CreateFont( _S("Tahoma") , 13 ) , img_res , make_rect<int>( 7 , 7 , TIPS_WIDTH , 1000 ) );
		m_tips->AddChild( layout );
		Attach( m_tips );
		m_tips->SetVisible( FALSE );
		m_tips->SetBackground( img_res->LoadImage( L"res/ui/theme/tips.tif" ) , Pair<int>(8,8) , Pair<int>(5,5) );
	}
	// ~XAppDesktop
	XAppDesktop::~XAppDesktop( void )
	{
	}
	// OnMouseInput
	HandleInput XAppDesktop::OnMouseInput( Updater& updater )
	{
		const MouseInput& input = updater.GetMouseInput();
		if( input.GetState() & Input::INPUT_STATE_MOUSE || input.GetAction() == Input::ACTION_MOUSE_MOVE )
		{
			m_hoverTime = 0;

			if( m_tips->GetVisible() )
			{
				Rect<int> rect = m_tips->GetPlacement();
				rect.extend( Pair<int>( 10 , 10 ) );
				if( !rect.is_inside( input.GetPoint() ) )
				{
					ClearTips();
				}
			}
		}
		else
		{
			ClearTips();
		}
		m_cursor = input.GetPoint();
		return __super::OnMouseInput( updater );
	}
	// OnKeyInput
	HandleInput XAppDesktop::OnKeyInput( Updater& updater )
	{
		ClearTips();
		return __super::OnKeyInput( updater );
	}
	// Tick
	void XAppDesktop::Tick( Updater& updater , float dTime )
	{
		__super::Tick( updater , dTime );
		
		if( m_hoverTime > HOVER_TIME && m_hovering.IsValid() )
		{
			m_hovering->OnMouseHover( updater );
			m_hoverTime = HOVER_TIME;
		}
		else if( m_hoverTime != HOVER_TIME )
		{
			m_hoverTime += dTime;
		}
	}
	
	// Draw
	void XAppDesktop::Draw( Composition& composition )
	{
		__super::Draw( composition );
	}

	// RedrawAll
	void XAppDesktop::RedrawAll( void )
	{
		// draw all child window
		for( int i = (int)m_children.size() - 1 ; i >= 0 ; --i )
		{
			RefWeak<XFrame> frame = m_children[i];
			if( frame->GetVisible() )
			{
				frame->UpdateControl();
			}
		}
	}

	// Draw
	void XAppDesktop::Draw( RenderContext& rc )
	{
		COUNTER_GUARD( _S("desktop_draw") );

		BeginFrame( rc );
		{
			//COUNTER_SCOPE( _S("frames") );

			// Draw all child window
			for( int i = (int)m_children.size() - 1 ; i >= 0 ; --i )
			{
				RefWeak<XAppFrame> frame = m_children[i];

				if( frame->GetVisible() )
				{
					frame->Draw( rc , *this );
				}
			}

			//COUNTER_END();
		}
		EndFrame( rc );
	}
	// OnDrawBackground
	void XAppDesktop::OnDrawBackground( Composition& composition )
	{
		composition.graphics().SetCompositingMode( Gdiplus::CompositingModeSourceCopy );
		composition.graphics().Clear( Gdiplus::Color(0,0,0,0) );
		composition.graphics().SetCompositingMode( Gdiplus::CompositingModeSourceOver );
	}

	// RequestShow
	void XAppDesktop::RequestShow( RefWeak<XFrame> frame , bool show )
	{
		
	}

	// Attach
	void XAppDesktop::Attach( RefWeak<XFrame> frame )
	{
		XS_ASSERT( frame->IsA<XAppFrame>() );
		XForm::AddChild( frame );
		frame->RequestUpdate( frame , frame->GetBound() );
	}

	// Detach
	void XAppDesktop::Detach( RefWeak<XFrame> frame )
	{
		XS_ASSERT( frame->IsA<XAppFrame>() );
		XForm::DelChild( frame );
	}
	// SetAppDesktopSize
	void XAppDesktop::SetAppDesktopSize( RenderContext& rc , const Pair<int>& size )
	{
		__super::SetDesktopSize( size );
		Resize( rc , size );
	}
	// RequestFocus
	void XAppDesktop::RequestFocus( RefWeak<IGuiComp> comp , Updater& updater )
	{
		RefWeak<XAppFrame> prev = GetFocusing();
		__super::RequestFocus( comp , updater );
		if( prev.IsValid() && prev != comp )
		{
			prev->RequestUpdate( prev , prev->GetBound() );
		}
		RefWeak<XAppFrame> frame( comp );
		frame->RequestUpdate( frame , frame->GetBound() );

		if( m_tips->GetVisible() && comp != m_tips )
			ClearTips();
	}
	// ClearFocus
	void XAppDesktop::ClearFocus( Updater& updater )
	{
		UpdateGuard __guard( this , updater , GetPosition() + m_offset );

		// Clear focus & send focus out message.
		if( m_focusing.IsValid() )
		{
			m_focusing->OnFocusOut( updater , NULL );
			RequestUpdate( m_focusing , Rect<int>( 0 , 0 , m_focusing->GetSize() ) );
		}
		m_focusing = NULL;
		// Disable input mode.
		m_inputMode = false;


		if( m_tips->GetVisible() )
			ClearTips();
	}
	// RequestUpdate
	void XAppDesktop::RequestUpdate( RefWeak<IGuiComp> comp , const Rect<int>& region )
	{
		XS_ASSERT( comp->IsA<XFrame>() );
		RefWeak<XFrame> frame( comp );
		frame->RequestUpdate( frame , region );
	}

	// ShowWindowAfterEffect
	void XAppDesktop::ShowWindowAfterEffect( RefWeak<XFrame> frame , bool show )
	{
		if( show )
		{
			frame->SetEnable( true );
			m_hidden.erase( frame );
			frame->BringToFront();
		}
		else
		{
			frame->SetVisible( false );
			m_hidden.insert( frame );
		}
		Updater updater( this );
		RequestFocus( frame , updater );
	}

	// ShowWindow
	void XAppDesktop::ShowWindow( RefWeak<XFrame> frame , bool show , bool animate )
	{
		if( frame->GetParent() != this )
		{
			TRACE_ERROR( _S("XAppDesktop::ShowWindow: Cannot show non-child frame.") );
			return;
		}
		
		if( frame->GetVisible() == show )
			return;

		RefWeak<XAppFrame> appframe( frame );
		if( appframe->GetEffect().IsValid() )
			return;

		appframe->SetEnable( false );
		if( show )
		{
			appframe->SetVisible( true );
		}
		if( animate )
		{
			if( appframe->IsA<XAppPopup>() )
			{
				Ref<XGfxShow> showFx = new XGfxShow;
				showFx->SetComp( frame );
				showFx->SetParam( _S("type") , new CVar( int( show ? XGfxFade::FADE_IN : XGfxFade::FADE_OUT ) ) );
				showFx->SetParam( _S("magnify") , new CVar( -20.f ) );
				appframe->AttachEffect( showFx , bind( &XAppDesktop::ShowWindowAfterEffect , this , frame , show ) );
			}
			else
			{
				Ref<XGfxSlide> showFx = new XGfxSlide;
				showFx->SetComp( frame );
				showFx->SetParam( _S("type") , new CVar( int( show ? XGfxSlide::SLIDE_IN : XGfxSlide::SLIDE_OUT ) ) );
				showFx->SetParam( _S("pos") , new CVar( Pair<float>( 700 , 600 ) ) );
				showFx->SetParam( _S("scale") , new CVar( Pair<float>( 64 , 64 ) ) );
				appframe->AttachEffect( showFx , bind( &XAppDesktop::ShowWindowAfterEffect , this , frame , show ) );
			}
		}
		else
		{
			ShowWindowAfterEffect( frame , show );
		}
	}

	// PinWindow
	void XAppDesktop::PinWindow( RefWeak<XFrame> frame , bool pin )
	{

	}
	// TrackTips
	void XAppDesktop::TrackTips( RefWeak<IGuiComp> comp , const WString& tips )
	{
		Pair<int> cursor = m_cursor;
		Pair<int> pos = comp->GetScreenPosition();

		RefWeak<XTagLayout> layout = m_tips->GetChild(0);

		layout->Clear();
		layout->SetSize( Pair<int>( TIPS_WIDTH , 1000 ) );
		layout->SetText( tips );

		size_t line = layout->GetLineCount();
		if( line == 0 )
			return;

		int width = int( layout->GetLineWidth(0) );
		int height = int( layout->GetLayoutHeight() );
		
		for( size_t i = 0 ; i < line ; ++i )
		{
			width = max<int>( width , int( layout->GetLineWidth(i) ) );
		}

		layout->SetSize( Pair<int>( width + 10 , height + 5 ) );
		m_tips->SetSize( Pair<int>( width + 10 + 8 , height + 5 + 8 ) );

		pos.x = ( m_cursor.x + pos.x ) / 2;
		pos.y = m_cursor.y + 10;
		m_tips->SetPosition( pos );

		m_tips->BringToFront();
		ReorderChildren();
		ShowWindow( m_tips , true , true );
	}
	// ClearTips
	void XAppDesktop::ClearTips( void )
	{
		ShowWindow( m_tips , false , true );
	}
	

} // namespace xeres
